use std::borrow::Cow;

use solutiont7::*;

const INVALID: &str = "身份证号码错误";

pub fn check_id_card(id_card_no: &str) -> String {
    if !check_validity(id_card_no) {
        return INVALID.to_string();
    }
    let head = "身份证号码正确";
    let gender = geneder(id_card_no);
    let (year, month, day) = year_month_day(id_card_no);
    let province = get_province(id_card_no);
    let city = get_city(id_card_no).unwrap_or("市辖区");
    let Some(district) = get_district(id_card_no) else {
        return INVALID.to_string();
    };
    let districts = [province, Some(city), Some(district)]
        .into_iter()
        .flatten()
        .collect::<Vec<_>>()
        .join("-");
    format!("身份证号码正确,{gender},{year}年{month}月{day}日,{districts}")
}

fn check_validity(id_card_no: &str) -> bool {
    if id_card_no.len() == 15 {
        return true;
    }
    let id_card_no = id_card_no.as_bytes();
    let weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
    let map = b"10X98765432";
    if id_card_no.len() != 18 {
        return false;
    }
    let mut ans = 0_u32;
    for (&id, weight) in std::iter::zip(&id_card_no[..17], weights) {
        if !id.is_ascii_digit() {
            return false;
        }
        ans += ((id - b'0') * weight) as u32;
    }
    map[(ans % 11) as usize] == id_card_no[17]
}

fn geneder(id_card_no: &str) -> &'static str {
    let gender_byte = if id_card_no.len() == 15 {
        id_card_no.as_bytes()[14]
    } else {
        id_card_no.as_bytes()[16]
    };
    if (gender_byte - b'0') % 2 == 0 {
        "女"
    } else {
        "男"
    }
}

fn year_month_day(id_card_no: &str) -> (Cow<'_, str>, &str, &str) {
    if id_card_no.len() == 15 {
        let year = &id_card_no[6..8];
        let month = &id_card_no[8..10];
        let day = &id_card_no[10..12];
        (format!("19{}", year).into(), month, day)
    } else {
        let year = &id_card_no[6..10];
        let month = &id_card_no[10..12];
        let day = &id_card_no[12..14];
        (year.into(), month, day)
    }
}
